package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.api.ApArticleFeign;
import com.heima.api.TaskFeign;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.schedule.dtos.TaskDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.service.AutomaticNewsReview;
import com.heima.wemedia.service.IWmChannelService;
import com.heima.wemedia.service.IWmNewsService;
import com.heima.wemedia.service.WmUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.io.ByteArrayInputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 21236
 */
@Service
@Slf4j
public class AutomaticNewsReviewImpl implements AutomaticNewsReview {

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IWmNewsService wmNewsService;

    @Autowired
    private ApArticleFeign client;

    @Autowired
    private WmUserService wmUserService;

    @Autowired
    private IWmChannelService channelService;

    @Autowired
    private WmSensitiveMapper sensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    private TaskFeign taskFeign;

    private static final String CONTENT_TYPE = "type";
    private static final String CONTENT_VALUE = "value";
    private static final String CONTENT_TYPE_TEXT = "text";
    private static final String CONTENT_TYPE_IMAGE = "image";


    /**
     * 文章内容及图片审核
     *
     * @param wmnews
     */
    @Override
    @Async("myTaskPool")
    public void reviewTextAndImages(WmNews wmnews) {

        String content = wmnews.getContent();
        Set<String> images = new TreeSet<>();
        StringBuilder text = new StringBuilder().append(wmnews.getTitle()).append("-").append(wmnews.getLabels());
        //处理内容中的文本及图片
        List<Map> mapList = JSONArray.parseArray(content, Map.class);
        for (Map map : mapList) {
            String type = (String) map.get(CONTENT_TYPE);
            if (CONTENT_TYPE_TEXT.equals(type)) {
                text.append("-").append((String) map.get(CONTENT_VALUE));
            } else if (CONTENT_TYPE_IMAGE.equals(type)) {
                images.add((String) map.get(CONTENT_VALUE));
            }
        }
        //处理封面中的图片
        String coverImage = wmnews.getImages();
        String[] strings = StringUtils.commaDelimitedListToStringArray(coverImage);
        images.addAll(Arrays.asList(strings));

        try {
            //自定义敏感词审核
            if (sensitiveWordReview(images,wmnews, text)) return;

            //文本审核
            Map textMap = greenTextScan.greeTextScan(text.toString());
            String textSuggestion = (String) textMap.get("suggestion");
            if (contentReview(wmnews, textMap, textSuggestion)) return;

            //图片审核
            if (!CollectionUtils.isEmpty(images)) {
                List<byte[]> imageList = new ArrayList<>();
                for (String url : images) {
                    imageList.add(fileStorageService.downLoadFile(url));
                }
                    Map map = greenImageScan.imageScan(imageList);
                    String suggestion = (String) map.get("suggestion");
                    if (contentReview(wmnews, map, suggestion)) return;
            }
        } catch (Exception e) {
            log.error("审核接口异常",e);
            wmnews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
            wmNewsService.updateById(wmnews);
            return ;
        }
        if(wmnews.getPublishTime() != null){
            addTask(wmnews);
        }else {
            saveToApp(wmnews);
        }
    }

    private void addTask(WmNews wmnews) {
        TaskDto taskDto = new TaskDto();
        taskDto.setTaskType(20);
        taskDto.setParameters(String.valueOf(wmnews.getId()));
        taskDto.setExecuteTime(wmnews.getPublishTime());
        taskDto.setPriority(1);
        taskFeign.addTask(taskDto);
    }

    @Override
    public void saveToApp(WmNews wmnews) {
        //审核通过，发布文章，同步到文章微服务
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmnews, articleDto);
        articleDto.setAuthorId(wmnews.getUserId());
        WmUser user = wmUserService.getById(wmnews.getUserId());
        articleDto.setAuthorName(user == null ? null : user.getName());
        WmChannel channel = channelService.getById(wmnews.getChannelId());
        articleDto.setChannelName(channel == null ? null : channel.getName());
        articleDto.setLayout(wmnews.getType());
        articleDto.setPublishTime(LocalDateTime.now());
        articleDto.setContent(wmnews.getContent());
        ResponseResult result = client.syncFromNews(articleDto);
        //更新文章id到自媒体
        if (result.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long articleId = (Long) result.getData();
            wmnews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmnews.setArticleId(articleId);
            wmnews.setPublishTime(new Date());
            wmNewsService.updateById(wmnews);

            //审核通过，发送消息，异步生成静态页面
            wmnews.setEnable((short) 1);
            kafkaTemplate.send("article-enable-topic", JSON.toJSONString(wmnews));
        }
    }

    /**
     * 自定义敏感词审核
     *
     * @param wmNews
     * @param text
     * @return
     */
    private boolean sensitiveWordReview(Set<String> images,WmNews wmNews, StringBuilder text)throws Exception {
        //查询敏感词
        List<WmSensitive> wmSensitives = sensitiveMapper.selectList(null);
        if (CollectionUtils.isEmpty(wmSensitives)) return false;
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);

            if(!CollectionUtils.isEmpty(images)){
                for (String url : images) {
                    byte[] bytes = fileStorageService.downLoadFile(url);
                    String doOCR = tess4jClient.doOCR(ImageIO.read(new ByteArrayInputStream(bytes)));
                    text.append("-").append(doOCR);
                }
            }


        //校验
        Map<String, Integer> matchedWords = SensitiveWordUtil.matchWords(text.toString());
        if (CollectionUtils.isEmpty(matchedWords)) return false;

        //校验不通过
        wmNews.setReason("内容不合规," + matchedWords);
        wmNews.setStatus(WmNews.Status.FAIL.getCode());
        wmNewsService.updateById(wmNews);
        return true;
    }

    /**
     * 内容审核
     *
     * @param wmnews
     * @param map
     * @param suggestion
     * @return
     */
    private boolean contentReview(WmNews wmnews, Map map, String suggestion) {
        if ("review".equals(suggestion)) {
            //人工审核
            wmnews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
            wmNewsService.updateById(wmnews);
            return true;
        } else if ("block".equals(suggestion)) {
            //内容违规
            wmnews.setReason("内容不合规," + map.get("label"));
            wmnews.setStatus(WmNews.Status.FAIL.getCode());
            wmNewsService.updateById(wmnews);
            return true;
        }
        return false;
    }

}

